package org.moonlight.jvm.rtda.share;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.moonlight.jvm.rtda.exclusive.Slot;
import org.moonlight.jvm.rtda.share.heap.Class;
import org.moonlight.jvm.rtda.share.heap.Slots;
import org.moonlight.jvm.rtda.share.heap.classmember.Field;

import java.io.Serializable;

/**
 * Object 类
 *
 * @author Moonlight
 * @createTime 2023/8/30 10:16
 **/
@Getter
@Setter
@EqualsAndHashCode
public class Object implements Serializable {
    private Class clazz;
    private java.lang.Object data;
    private java.lang.Object extra;

    public Object() {}

    public Object(Class clazz) {
        this.clazz = clazz;
        this.data = new Slots(clazz.getInstanceSlotCount());
    }

    public Object(Class clazz, java.lang.Object data) {
        this.clazz = clazz;
        this.data = data;
    }

    public byte[] bytes() {
        return (byte[]) this.data;
    }

    public short[] shorts() {
        return (short[]) this.data;
    }

    public char[] chars() {
        return (char[]) this.data;
    }

    public int[] ints() {
        return (int[]) this.data;
    }

    public float[] floats() {
        return (float[]) this.data;
    }

    public double[] doubles() {
        return (double[]) this.data;
    }

    public long[] longs() {
        return (long[]) this.data;
    }

    public Object[] refs() {
        return (Object[]) this.data;
    }

    public Slots getFields() {
        return (Slots) this.data;
    }

    public int arrayLength() {
        if (this.data instanceof byte[]) {
            return bytes().length;
        }
        if (this.data instanceof char[]) {
            return chars().length;
        }
        if (this.data instanceof short[]) {
            return shorts().length;
        }
        if (this.data instanceof int[]) {
            return ints().length;
        }
        if (this.data instanceof float[]) {
            return floats().length;
        }
        if (this.data instanceof double[]) {
            return doubles().length;
        }
        if (this.data instanceof long[]) {
            return longs().length;
        }
        if (this.data instanceof Object[]) {
            return refs().length;
        }
        throw new RuntimeException("Not array");
    }

    public boolean isInstanceOf(Class clazz) {
        return clazz.isAssignableFrom(this.clazz);
    }

    public void setRefVal(String name, String descriptor, Object ref) {
        Field field = this.clazz.getField(name, descriptor, false);
        if (field != null) {
            Slots fields = this.getFields();
            fields.setRef(field.getSlotId(), ref);
            return;
        }
        throw new RuntimeException("根据 name: " + name + " descriptor: " + descriptor + " isStatic: false 在类[" + this.clazz.getName() + "]中找不到对应的字段");
    }

    public Object getRefVal(String name, String descriptor) {
       Field field = this.clazz.getField(name, descriptor);
       if (field != null) {
           Slots fields = this.getFields();
           return fields.getRef(field.getSlotId());
       }
       throw new RuntimeException("根据 name: " + name + " descriptor: " + descriptor + " 在类[" + this.clazz.getName() + "]中找不到对应的字段");
    }

    public Object myClone() {
        System.out.println("this is my clone method XDDDDDDDDD");
        return new Object(this.clazz, this.cloneData());
    }

    private java.lang.Object cloneData() {
        if (this.data instanceof byte[]) {
            byte[] ori = (byte[]) this.data;
            byte[] target = new byte[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof char[]) {
            char[] ori = (char[]) this.data;
            char[] target = new char[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof short[]) {
            short[] ori = (short[]) this.data;
            short[] target = new short[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof int[]) {
            int[] ori = (int[]) this.data;
            int[] target = new int[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof float[]) {
            float[] ori = (float[]) this.data;
            float[] target = new float[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof double[]) {
            double[] ori = (double[]) this.data;
            double[] target = new double[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof long[]) {
            long[] ori = (long[]) this.data;
            long[] target = new long[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        if (this.data instanceof Object[]) {
            Object[] ori = (Object[]) this.data;
            Object[] target = new Object[ori.length];
            System.arraycopy(ori, 0, target, 0, ori.length);
            return target;
        }
        Slots data = (Slots) this.data;
        Slot[] oriSlots = data.getSlots();
        Slot[] target = new Slot[oriSlots.length];
        System.arraycopy(oriSlots, 0, target, 0, oriSlots.length);
        return new Slots(target);
    }
}